﻿/*************************************************************************************
 * 文 件 名:   HK_SlidePage
 * 
 * 描    述:   图片轮播展示功能脚本
 * 
 * 版    本：  V1.1
 * 创 建 者：  京产肠饭、谭潇杰
 * 创建时间：  2021/12/23
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using System.Collections.Generic;
using UnityEngine.EventSystems;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

namespace HKTools
{
    [RequireComponent(typeof(RectTransform))]
    public class HK_SlidePage : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    {
        public enum MoveType
        {
            Loop,         //循环
            PingPong,     //来回往复
        }

        public enum MoveDir
        {
            Left,
            Right,
        }

        [Header("切换方式："), SerializeField] MoveType moveType = MoveType.PingPong;

        [Header("图集父物体："), SerializeField] RectTransform content;
        GridLayoutGroup grid;

        [Header("上一页按钮："), SerializeField] Button lastPage_Btn;
        [Header("下一页按钮："), SerializeField] Button nextPage_Btn;

        [Header("页码单选ToggleGroup："), SerializeField] ToggleGroup pageToggleGroup;
        List<Toggle> pageToggleList;

        [Header("自动轮播时长："), SerializeField] float pageStayTime = 2.0f;

        [Header("是否自动轮播："), SerializeField] bool isAutoSlide = false;

        [Header("是否允许拖动切页："), SerializeField] bool isAllowDrag = true;
        bool isDraging = false;

        [Header("是否启用切页动画："), SerializeField] bool isUseAnim = false;
        bool isAniming = false;

        // 自动轮播方向，-1表示向左，1表示向右
        MoveDir moveDir = MoveDir.Right;

        // 最大页码
        int maxPageIndex = 0;
        // 当前显示页的页码，下标从0开始
        int curPageIndex = 0;
        public int CurPageIndex
        {
            get { return curPageIndex; }
            set
            {
                curPageIndex = value;

                if (curPageIndex <= 0)
                {
                    curPageIndex = 0;

                    lastPage_Btn.gameObject.SetActive(false);
                    nextPage_Btn.gameObject.SetActive(true);
                }
                else if (curPageIndex >= maxPageIndex)
                {
                    if (moveType == MoveType.PingPong)
                        curPageIndex = maxPageIndex;

                    lastPage_Btn.gameObject.SetActive(true);
                    nextPage_Btn.gameObject.SetActive(false);
                }
                else
                {
                    lastPage_Btn.gameObject.SetActive(true);
                    nextPage_Btn.gameObject.SetActive(true);
                }
            }
        }

        float recordTime = 0f;

        List<float> childItemPosX_List = new List<float>();

        //如果是Loop 判定当前是否已经实例化出来
        bool isAddChild = false;

        void Awake()
        {
            grid = content.GetComponent<GridLayoutGroup>();

            // 根据GridLayout初始化所有图的初始位置  
            int childCount = content.transform.childCount;
            float cellSizeX = grid.cellSize.x;
            float spacingX = grid.spacing.x;
            float posX = -cellSizeX * 0.5f;

            childItemPosX_List.Clear();
            childItemPosX_List.Add(posX);

            for (int i = 1; i <= childCount; i++)
            {
                //如果是Loop，多计算一个位置出来
                if (moveType != MoveType.Loop && i == childCount)
                    continue;

                posX -= cellSizeX + spacingX;
                childItemPosX_List.Add(posX);
            }

            lastPage_Btn.onClick.AddListener(() =>
            {
                CurPageIndex--;
                SwitchToPageNum();
            });

            nextPage_Btn.onClick.AddListener(() =>
            {
                CurPageIndex++;
                SwitchToPageNum();
            });

            if (pageToggleGroup.transform.childCount > 0)
            {
                pageToggleList = new List<Toggle>();

                for (int i = 0; i < pageToggleGroup.transform.childCount; i++)
                {
                    Toggle childToggle = pageToggleGroup.transform.GetChild(i).GetComponent<Toggle>();

                    pageToggleList.Add(childToggle);

                    int targetPageNum = i;

                    childToggle.onValueChanged.AddListener(isOn =>
                    {
                        if (!isOn)
                            return;

                        try
                        {
                            if (EventSystem.current.currentSelectedGameObject != childToggle.gameObject)
                                return;

                            CurPageIndex = targetPageNum;
                            SwitchToPageNum();
                        }
                        catch
                        {

                        }
                    });
                }

                maxPageIndex = pageToggleList.Count - 1;
            }

            CurPageIndex = 0;
        }

        void Update()
        {
            if (!isAutoSlide || isDraging)
                return;

            if (Time.time > recordTime + pageStayTime)
            {
                recordTime = Time.time;

                // 如果是PingPong运动模式，则在运动到两头的时候改变方向
                if (moveType == MoveType.PingPong)
                {
                    if (CurPageIndex == 0)
                        moveDir = MoveDir.Right;
                    else if (CurPageIndex == maxPageIndex)
                        moveDir = MoveDir.Left;
                }

                if (moveDir == MoveDir.Left)
                {
                    CurPageIndex--;
                }
                else if (moveDir == MoveDir.Right)
                {
                    CurPageIndex++;
                }

                SwitchToPageNum();
            }
        }

        /// <summary>
        /// 切换至某页
        /// </summary>
        void SwitchToPageNum()
        {
            Vector3 pos = content.localPosition;

            if (moveType == MoveType.Loop && CurPageIndex == maxPageIndex)
                AddChildTempItem();

            if (isUseAnim)
            {
                if (moveType == MoveType.Loop && CurPageIndex > maxPageIndex)  //如果移动到最后
                {
                    isAniming = true;
                    content.DOLocalMoveX(childItemPosX_List[CurPageIndex], 0.5f)
                        .OnComplete(() =>
                        {
                            content.localPosition = new Vector3(childItemPosX_List[0], pos.y, pos.z);
                            isAniming = false;
                        });
                    CurPageIndex = 0;
                }
                else
                {
                    isAniming = true;
                    content.DOLocalMoveX(childItemPosX_List[CurPageIndex], 0.5f)
                        .OnComplete(() => isAniming = false);
                }
            }
            else
            {
                if (moveType == MoveType.Loop && CurPageIndex > maxPageIndex) //移动到最后
                {
                    content.localPosition = new Vector3(childItemPosX_List[0], pos.y, pos.z);
                    CurPageIndex = 0;
                }
                else
                {
                    content.localPosition = new Vector3(childItemPosX_List[CurPageIndex], pos.y, pos.z);
                }
            }

            recordTime = Time.time;//重新计时
            pageToggleList[CurPageIndex].isOn = true;
        }

        void AddChildTempItem()
        {
            if (!isAddChild)
            {
                Instantiate(content.GetChild(0).gameObject, content.transform);
                isAddChild = true;
            }
        }

        Vector3 originDragPos = Vector3.zero;

        public void OnPointerDown(PointerEventData eventData)
        {
            if (!isAllowDrag || isAniming)
                return;

            if (eventData.button != PointerEventData.InputButton.Left)
                return;

            isDraging = true;
            originDragPos = eventData.position;
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            if (isAniming)
                return;

            Vector3 desDragPos = eventData.position;

            if (desDragPos.x > originDragPos.x)
            {
                CurPageIndex--;
            }
            else
            {
                CurPageIndex++;
            }

            SwitchToPageNum();

            isDraging = false;
        }
    }
}